const zlib = require('zlib');
const fs = require('fs');
const crc = require('./crc');

function ihdr(width = 0,
  height = 0,
  bitDepth = 8,
  colourType = 6,
  compressionMethod = 0,
  filterMethod = 0,
  interlaceMethod = 0) {
  const buf = Buffer.allocUnsafe(17);

  buf.write('IHDR', 0);

  buf.writeUInt32BE(width, 4);
  buf.writeUInt32BE(height, 8);
  buf.writeUInt8(bitDepth, 12);
  buf.writeUInt8(colourType, 13);
  buf.writeUInt8(compressionMethod, 14);
  buf.writeUInt8(filterMethod, 15);
  buf.writeUInt8(interlaceMethod, 16);

  const ihdrCrc = Buffer.allocUnsafe(4);
  ihdrCrc.writeInt32BE(crc(buf));
  return Buffer.concat([Buffer.from([0, 0, 0, 13]), buf, ihdrCrc]);
}

module.exports = class {
  constructor(width, height) {
    this.width = width;
    this.height = height;

    this.ihdr = ihdr(width, height);
    this.idat = Buffer.alloc((width * height * 4) + height, 255);
  }

  setPixel(x, y, pixel) {
    const pos = (this.width * y * 4) + y + 1 + (x * 4);
    this.idat.writeUInt32BE(pixel, pos);
  }

  getIdat() {
    const idatName = Buffer.from('IDAT');
    const idatData = zlib.deflateSync(this.idat);
    const idatLen = Buffer.alloc(4);
    idatLen.writeUInt32BE(this.idat.byteLength);
    const idatCrc = Buffer.allocUnsafe(4);
    idatCrc.writeInt32BE(crc(Buffer.concat([idatName, this.idat])));
    return Buffer.concat([idatLen, idatName, idatData, idatCrc]);
  }
  writeFile(path) {
    const idat = this.getIdat();

    const buf = Buffer.concat([
      Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
      this.ihdr,
      idat,
      Buffer.from('IEND'),
    ]);

    fs.writeFileSync(path, buf);
  }
};